package com.sy.simpleegg.serialport.base

import com.sy.simpleegg.controllermanager.helper.ControlHelper
import com.sy.logger.Logger
import com.sy.simpleegg.ext.logFile
import com.sy.simpleegg.serialport.Config
import com.sy.simpleegg.serialport.bean.ComData
import com.sy.simpleegg.util.ByteUtil
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.cnbleu.serialport.SerialPort.BAUDRATE
import org.cnbleu.serialport.SerialPort.DATAB
import org.cnbleu.serialport.SerialPort.PARITY
import org.cnbleu.serialport.SerialPort.STOPB
import java.util.Queue
import java.util.concurrent.LinkedBlockingDeque

/**
 * 串口控制基类
 */
abstract class BaseController (
    private val portName: String,
    private val baudrate: BAUDRATE,
    private val stopb: STOPB,
    private val datab: DATAB,
    private val parity: PARITY,
    private val speed: Long?
){

    /**
     * 串口助手
     */
    private var controlHelper: ControlHelper? = null
    /**
     *
     */
    var mCoroutineScope = MainScope()
    /**
     * 接收串口数据处理线程
     */
    private var dataHandlerJob: Job? = null
    /**
     * 指令超时处理线程
     */
    private var timeOutJob: Job? = null
    /**
     * 指令发送线程
     */
    private var sendJob: Job? = null
    /**
     * 接收到的串口数据链表
     */
    private var dataQueue: Queue<ComData> = LinkedBlockingDeque()
    /**
     * 发送指令链表
     */
    private var sendDataQueue: Queue<ComData> = LinkedBlockingDeque()
    /**
     * 接收串口数据处理间隔
     */
    private var msgHandleInterval: Long = Config.MSG_HANDLE_INTERVAL
    /**
     * 指令超时时间
     */
    private var timeout: Long = Config.CMD_TIMEOUT
    /**
     * 发送指令间隔
     */
    private var sendInterval: Long = Config.SEND_INTERVAL
    /**
     * 是否开启指令超时
     * 根据需求决定是否开启超时
     * 开启超时：同步发送指令
     * 关闭超时：异步发送指令
     */
    private var openTimeout: Boolean = false
    /**
     * 指令响应超时判断函数，每个指令的响应数据可能不同，需要分开判断
     */
    private var actionTimeout: ((respCmd: ComData) -> Boolean)? = null
    /**
     * 当前发送的指令数据
     */
    private var currentSendData: ComData? = null
    /**
     * 是否收到响应数据，只有开启超时后才处理
     */
    private var isRespon: Boolean = true
    /**
     * 是否开启队列指令
     * 开启：每个指令放入队列中，排队执行指令
     * 关闭：每次只处理一个指令，处理指令时不接收其他指令
     */
    private var isSortCmd: Boolean = false

    init {
        try {
            openDataHandler()
            openSendHandler()
            controlHelper = ControlHelper(object : ControlHelper.OnDataReceivedListener{
                override fun onDataReceived(data: ByteArray) {
                    val comData = ComData(portName, data)
//                    onDataReceived(comData)
                    if (openTimeout && actionTimeout != null && !isRespon){
                        if (actionTimeout!!.invoke(comData)){
                            timeOutJob?.cancel()
                            isRespon = true
                        }
                    }
                    dataQueue.add(comData)
                }
            })

            controlHelper?.apply {
                setPort(portName)
                setBaudRate(baudrate)
                setStopB(stopb)
                setDataB(datab)
                setParity(parity)
                speed?.let {
                    setReadSpeed(it)
                }
                open()
            }
        }catch (e: Exception){
            e.printStackTrace()
            Logger.d("BaseController初始化异常：" + e.message)
        }
    }

    /**
     * 打开接收串口数据处理
     */
    private fun openDataHandler(){
        dataHandlerJob?.cancel()

        dataHandlerJob = mCoroutineScope.launch (Dispatchers.IO){
            while (true){
                try {
                    if (dataQueue.size > 0) {
                        var comData: ComData? = null
                        while (dataQueue.poll().also { comData = it } != null) {
                            comData?.let {
                                onDataReceived(it)
                            }
                        }
                    }
                    delay(msgHandleInterval)
                }catch (e: Exception){
                    e.printStackTrace()
                    logFile("串口数据处理异常：${e.message}")
                }
            }
        }
    }

    /**
     * 打开接收串口数据处理
     */
    private fun openSendHandler(){
        sendJob?.cancel()

        sendJob = mCoroutineScope.launch (Dispatchers.IO) {
            while (true){
                try {
                    run loop@{
                        if (sendDataQueue.size > 0 && isRespon) {
                            var comData: ComData? = null
                            while (isRespon && sendDataQueue.poll().also { comData = it } != null) {
                                isRespon = false
                                currentSendData = comData
                                val timeout = currentSendData?.timeout?:0L
                                startTimeout(timeout)
                                comData?.data?.let { send(it) }
                                delay(sendInterval)
                                return@loop
                            }
                        }
                        delay(sendInterval)
                    }
                }catch (e: Exception){
                    e.printStackTrace()
                    logFile("${javaClass.simpleName} 发送指令控制器异常：${e.message}")
                    isRespon = true
                }
            }
        }
    }

    /**
     * 发送指令
     */
    fun sendData(data: ByteArray, timeout: Long){
        try {
            if (openTimeout){
                if (isSortCmd) {
                    //队列指令，把每个指令放入队列中，排队执行
                    sendDataQueue.add(ComData(portName, data, timeout))
                }else{
                    //非队列指令，有指令正在处理时，不继续接收指令
                    if (isRespon) {
                        sendDataQueue.add(ComData(portName, data, timeout))
                    }
                }
            }else {
                send(data)
            }
        }catch (e: Exception){
            e.printStackTrace()
            logFile("${javaClass.simpleName} 发送指令异常：${e.message}")
        }
    }

    /**
     * 发送指令
     */
    private fun send(data: ByteArray){
        logFile("发送指令：${ByteUtil.bytes2HexStr(data)}")
        controlHelper?.send(data)
    }

    /**
     * 发送心跳指令专用
     */
    fun heartBeat(data: ByteArray){
        send(data)
    }

    /**
     * 设置接收串口数据处理间隔
     */
    fun setMsgHandleInterval(interval: Long){
        msgHandleInterval = interval
    }

    fun setOpenTimeout(open: Boolean){
        openTimeout = open
    }

    fun setActionTimeout(action: ((respCmd: ComData) -> Boolean)?){
        actionTimeout = action
    }

    /**
     * 开始指令超时倒计时
     */
    private fun startTimeout(time: Long){
        if (time <= 0){
            return
        }
        timeOutJob?.cancel()

        timeOutJob = mCoroutineScope.launch (Dispatchers.IO) {
            try {
                delay(time)
                currentSendData?.let {
                    cmdTimeout(it)
                }
                isRespon = true
            }catch (e: Exception){
                e.printStackTrace()
                logFile("指令超时计时异常：${e.message}")
            }
        }
    }

    fun close(){
        mCoroutineScope.cancel()
        controlHelper?.close()
    }

    abstract fun onDataReceived(comData: ComData)

    abstract fun cmdTimeout(comData: ComData)

}